<?php declare(strict_types=1);

namespace Zyucv7\Core\Filesystem;

use FilesystemIterator;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
use UnexpectedValueException;

/**
 * Directory
 *
 * 一个用于处理目录操作的PHP模块，兼容 PHP 7.x 和 8.x。
 * 提供创建、查看（支持递归）和删除（支持递归）目录的功能。
 *
 * @author Your Name
 * @version 1.0.0
 */
class Directory
{

    /**
     * 创建目录
     *
     * @param string $path 目录路径（完整路径）
     * @param int $permissions 目录权限，默认为 0755
     * @param bool $recursive 是否递归创建父目录，默认为 true
     * @return bool 成功返回 true，失败返回 false
     */
    public function create(string $path, int $permissions = 0755, bool $recursive = true): bool
    {
        // 如果目录已存在，则认为创建成功
        if (is_dir($path)) {
            return true;
        }

        // 使用 mkdir 内置函数创建目录
        // @ 抑制警告，因为我们会通过返回值来判断是否成功
        return mkdir($path, $permissions, $recursive);
    }

    /**
     * 查看目录内容
     *
     * @param string $path 目录路径（完整路径）
     * @param bool $recursive 是否递归查看所有子目录，默认为 false
     * @return array 返回包含文件和目录信息的数组。失败或目录不存在则返回空数组。
     *               数组元素格式: ['path' => string, 'type' => 'file'|'dir', 'size' => int, 'modified' => int]
     */
    public function view(string $path, bool $recursive = false): array
    {
        if (!is_dir($path)) {
            return [];
        }

        $contents = [];

        try {
            if ($recursive) {
                // 递归迭代器，CHILD_FIRST 模式确保在处理目录前先处理其内容（虽然这里只是读取）
                $iterator = new RecursiveIteratorIterator(
                    new RecursiveDirectoryIterator($path, FilesystemIterator::SKIP_DOTS),
                    RecursiveIteratorIterator::SELF_FIRST
                );
            } else {
                // 非递归文件系统迭代器
                $iterator = new FilesystemIterator($path, FilesystemIterator::SKIP_DOTS);
            }

            /** @var SplFileInfo $fileInfo */
            foreach ($iterator as $fileInfo) {
                $contents[] = [
                    'name'     => $fileInfo->getFilename(),
                    'path'     => $fileInfo->getPathname(),
                    'type'     => $fileInfo->isDir() ? 'dir' : 'file',
                    'size'     => $fileInfo->getSize(),
                    'modified' => $fileInfo->getMTime(),
                ];
            }
        } catch (UnexpectedValueException $e) {
            // 如果目录因权限问题无法打开，迭代器会抛出此异常
            // 记录错误或返回空数组
            // error_log($e->getMessage());
            return [];
        }

        // 对结果进行排序：目录优先，然后按路径名排序
        usort($contents, function ($a, $b) {
            if ($a['type'] === $b['type']) {
                return strcmp($a['path'], $b['path']);
            }
            return ($a['type'] === 'dir') ? -1 : 1;
        });

        return $contents;
    }

    /**
     * 删除目录
     *
     * @param string $path 目录路径（完整路径）
     * @param bool $recursive 是否递归删除目录及其所有内容，默认为 false
     * @return bool 成功返回 true，失败返回 false
     */
    public function delete(string $path, bool $recursive = false): bool
    {
        if (!is_dir($path)) {
            // 如果目录不存在，可以认为删除成功，或者返回 false。这里返回 true。
            return true;
        }

        if (!$recursive) {
            // 非递归删除，只能删除空目录
            return @rmdir($path);
        }

        // --- 递归删除逻辑 ---
        try {
            $iterator = new RecursiveIteratorIterator(
                new RecursiveDirectoryIterator($path, FilesystemIterator::SKIP_DOTS),
                RecursiveIteratorIterator::CHILD_FIRST // 从子节点开始遍历
            );

            /** @var SplFileInfo $fileInfo */
            foreach ($iterator as $fileInfo) {
                if ($fileInfo->isDir()) {
                    // 删除目录
                    if (!@rmdir($fileInfo->getRealPath())) {
                        return false; // 删除失败，中止操作
                    }
                } else {
                    // 删除文件
                    if (!@unlink($fileInfo->getRealPath())) {
                        return false; // 删除失败，中止操作
                    }
                }
            }
        } catch (UnexpectedValueException $e) {
            // error_log($e->getMessage());
            return false;
        }

        // 最后删除目标目录本身
        return @rmdir($path);
    }
}
